{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c45f0998",
   "metadata": {},
   "source": [
    "### Relevant Python 3.9 Changes"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e965eba",
   "metadata": {},
   "source": [
    "The release of Python 3.9 has brought some new features.\n",
    "\n",
    "This is a summary of the ones _I_ deemed relevant to this course, and does **not** include all the changes!\n",
    "\n",
    "For full release details, see [here](https://docs.python.org/3/whatsnew/3.9.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39255227",
   "metadata": {},
   "source": [
    "#### Time Zones"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26750adb",
   "metadata": {},
   "source": [
    "We don't cover 3rd party libraries in this course, but if you've worked with Python in a production environment, you will likely have come across the dreaded timezone and Daylight Savings issues that plague datetimes!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cdfe8a5",
   "metadata": {},
   "source": [
    "Most likely you will have resorted to using the `pytz` and `python-dateutil` libraries to help with that."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc000883",
   "metadata": {},
   "source": [
    "Now, Python 3.9 is proud to introduce the `zoneinfo` module to deal with timezones properly. About time too!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2d652dd",
   "metadata": {},
   "source": [
    "For full info on this, refer to [PEP 615](https://peps.python.org/pep-0615/).\n",
    "\n",
    "And the Python [docs](https://docs.python.org/3.9/library/zoneinfo.html#module-zoneinfo).\n",
    "\n",
    "**Windows Users**: you will likely need to add a dependency on the `tzdata` [library](https://pypi.org/project/tzdata/) for the IANA time zone database. See [this note](https://docs.python.org/3.9/library/zoneinfo.html#data-sources)\n",
    "\n",
    "You should also take a look at this [presentation](https://pganssle-talks.github.io/chipy-nov-2020-zoneinfo/#/) by Paul Ganssle who wrote that module - very interesting read!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80255944",
   "metadata": {},
   "source": [
    "Let's look at how we might have handled timezone and DST using `pytz` and `dateutil`, and contrast that to how we can use the new `zoneinfo` module instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "ec129288",
   "metadata": {},
   "outputs": [],
   "source": [
    "import zoneinfo\n",
    "from datetime import datetime, timezone\n",
    "from zoneinfo import ZoneInfo\n",
    "\n",
    "import dateutil\n",
    "import pytz"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "beadc4e2",
   "metadata": {},
   "source": [
    "Let's list out all the defined time zones:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d0058e73",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Africa/Abidjan\n",
      "Africa/Accra\n",
      "Africa/Addis_Ababa\n",
      "Africa/Algiers\n",
      "Africa/Asmara\n",
      "Africa/Asmera\n",
      "Africa/Bamako\n",
      "Africa/Bangui\n",
      "Africa/Banjul\n",
      "Africa/Bissau\n",
      "Africa/Blantyre\n",
      "Africa/Brazzaville\n",
      "Africa/Bujumbura\n",
      "Africa/Cairo\n",
      "Africa/Casablanca\n",
      "Africa/Ceuta\n",
      "Africa/Conakry\n",
      "Africa/Dakar\n",
      "Africa/Dar_es_Salaam\n",
      "Africa/Djibouti\n",
      "Africa/Douala\n",
      "Africa/El_Aaiun\n",
      "Africa/Freetown\n",
      "Africa/Gaborone\n",
      "Africa/Harare\n",
      "Africa/Johannesburg\n",
      "Africa/Juba\n",
      "Africa/Kampala\n",
      "Africa/Khartoum\n",
      "Africa/Kigali\n",
      "Africa/Kinshasa\n",
      "Africa/Lagos\n",
      "Africa/Libreville\n",
      "Africa/Lome\n",
      "Africa/Luanda\n",
      "Africa/Lubumbashi\n",
      "Africa/Lusaka\n",
      "Africa/Malabo\n",
      "Africa/Maputo\n",
      "Africa/Maseru\n",
      "Africa/Mbabane\n",
      "Africa/Mogadishu\n",
      "Africa/Monrovia\n",
      "Africa/Nairobi\n",
      "Africa/Ndjamena\n",
      "Africa/Niamey\n",
      "Africa/Nouakchott\n",
      "Africa/Ouagadougou\n",
      "Africa/Porto-Novo\n",
      "Africa/Sao_Tome\n",
      "Africa/Timbuktu\n",
      "Africa/Tripoli\n",
      "Africa/Tunis\n",
      "Africa/Windhoek\n",
      "America/Adak\n",
      "America/Anchorage\n",
      "America/Anguilla\n",
      "America/Antigua\n",
      "America/Araguaina\n",
      "America/Argentina/Buenos_Aires\n",
      "America/Argentina/Catamarca\n",
      "America/Argentina/ComodRivadavia\n",
      "America/Argentina/Cordoba\n",
      "America/Argentina/Jujuy\n",
      "America/Argentina/La_Rioja\n",
      "America/Argentina/Mendoza\n",
      "America/Argentina/Rio_Gallegos\n",
      "America/Argentina/Salta\n",
      "America/Argentina/San_Juan\n",
      "America/Argentina/San_Luis\n",
      "America/Argentina/Tucuman\n",
      "America/Argentina/Ushuaia\n",
      "America/Aruba\n",
      "America/Asuncion\n",
      "America/Atikokan\n",
      "America/Atka\n",
      "America/Bahia\n",
      "America/Bahia_Banderas\n",
      "America/Barbados\n",
      "America/Belem\n",
      "America/Belize\n",
      "America/Blanc-Sablon\n",
      "America/Boa_Vista\n",
      "America/Bogota\n",
      "America/Boise\n",
      "America/Buenos_Aires\n",
      "America/Cambridge_Bay\n",
      "America/Campo_Grande\n",
      "America/Cancun\n",
      "America/Caracas\n",
      "America/Catamarca\n",
      "America/Cayenne\n",
      "America/Cayman\n",
      "America/Chicago\n",
      "America/Chihuahua\n",
      "America/Coral_Harbour\n",
      "America/Cordoba\n",
      "America/Costa_Rica\n",
      "America/Creston\n",
      "America/Cuiaba\n",
      "America/Curacao\n",
      "America/Danmarkshavn\n",
      "America/Dawson\n",
      "America/Dawson_Creek\n",
      "America/Denver\n",
      "America/Detroit\n",
      "America/Dominica\n",
      "America/Edmonton\n",
      "America/Eirunepe\n",
      "America/El_Salvador\n",
      "America/Ensenada\n",
      "America/Fort_Nelson\n",
      "America/Fort_Wayne\n",
      "America/Fortaleza\n",
      "America/Glace_Bay\n",
      "America/Godthab\n",
      "America/Goose_Bay\n",
      "America/Grand_Turk\n",
      "America/Grenada\n",
      "America/Guadeloupe\n",
      "America/Guatemala\n",
      "America/Guayaquil\n",
      "America/Guyana\n",
      "America/Halifax\n",
      "America/Havana\n",
      "America/Hermosillo\n",
      "America/Indiana/Indianapolis\n",
      "America/Indiana/Knox\n",
      "America/Indiana/Marengo\n",
      "America/Indiana/Petersburg\n",
      "America/Indiana/Tell_City\n",
      "America/Indiana/Vevay\n",
      "America/Indiana/Vincennes\n",
      "America/Indiana/Winamac\n",
      "America/Indianapolis\n",
      "America/Inuvik\n",
      "America/Iqaluit\n",
      "America/Jamaica\n",
      "America/Jujuy\n",
      "America/Juneau\n",
      "America/Kentucky/Louisville\n",
      "America/Kentucky/Monticello\n",
      "America/Knox_IN\n",
      "America/Kralendijk\n",
      "America/La_Paz\n",
      "America/Lima\n",
      "America/Los_Angeles\n",
      "America/Louisville\n",
      "America/Lower_Princes\n",
      "America/Maceio\n",
      "America/Managua\n",
      "America/Manaus\n",
      "America/Marigot\n",
      "America/Martinique\n",
      "America/Matamoros\n",
      "America/Mazatlan\n",
      "America/Mendoza\n",
      "America/Menominee\n",
      "America/Merida\n",
      "America/Metlakatla\n",
      "America/Mexico_City\n",
      "America/Miquelon\n",
      "America/Moncton\n",
      "America/Monterrey\n",
      "America/Montevideo\n",
      "America/Montreal\n",
      "America/Montserrat\n",
      "America/Nassau\n",
      "America/New_York\n",
      "America/Nipigon\n",
      "America/Nome\n",
      "America/Noronha\n",
      "America/North_Dakota/Beulah\n",
      "America/North_Dakota/Center\n",
      "America/North_Dakota/New_Salem\n",
      "America/Nuuk\n",
      "America/Ojinaga\n",
      "America/Panama\n",
      "America/Pangnirtung\n",
      "America/Paramaribo\n",
      "America/Phoenix\n",
      "America/Port-au-Prince\n",
      "America/Port_of_Spain\n",
      "America/Porto_Acre\n",
      "America/Porto_Velho\n",
      "America/Puerto_Rico\n",
      "America/Punta_Arenas\n",
      "America/Rainy_River\n",
      "America/Rankin_Inlet\n",
      "America/Recife\n",
      "America/Regina\n",
      "America/Resolute\n",
      "America/Rio_Branco\n",
      "America/Rosario\n",
      "America/Santa_Isabel\n",
      "America/Santarem\n",
      "America/Santiago\n",
      "America/Santo_Domingo\n",
      "America/Sao_Paulo\n",
      "America/Scoresbysund\n",
      "America/Shiprock\n",
      "America/Sitka\n",
      "America/St_Barthelemy\n",
      "America/St_Johns\n",
      "America/St_Kitts\n",
      "America/St_Lucia\n",
      "America/St_Thomas\n",
      "America/St_Vincent\n",
      "America/Swift_Current\n",
      "America/Tegucigalpa\n",
      "America/Thule\n",
      "America/Thunder_Bay\n",
      "America/Tijuana\n",
      "America/Toronto\n",
      "America/Tortola\n",
      "America/Vancouver\n",
      "America/Virgin\n",
      "America/Whitehorse\n",
      "America/Winnipeg\n",
      "America/Yakutat\n",
      "America/Yellowknife\n",
      "Antarctica/Casey\n",
      "Antarctica/Davis\n",
      "Antarctica/DumontDUrville\n",
      "Antarctica/Macquarie\n",
      "Antarctica/Mawson\n",
      "Antarctica/McMurdo\n",
      "Antarctica/Palmer\n",
      "Antarctica/Rothera\n",
      "Antarctica/South_Pole\n",
      "Antarctica/Syowa\n",
      "Antarctica/Troll\n",
      "Antarctica/Vostok\n",
      "Arctic/Longyearbyen\n",
      "Asia/Aden\n",
      "Asia/Almaty\n",
      "Asia/Amman\n",
      "Asia/Anadyr\n",
      "Asia/Aqtau\n",
      "Asia/Aqtobe\n",
      "Asia/Ashgabat\n",
      "Asia/Ashkhabad\n",
      "Asia/Atyrau\n",
      "Asia/Baghdad\n",
      "Asia/Bahrain\n",
      "Asia/Baku\n",
      "Asia/Bangkok\n",
      "Asia/Barnaul\n",
      "Asia/Beirut\n",
      "Asia/Bishkek\n",
      "Asia/Brunei\n",
      "Asia/Calcutta\n",
      "Asia/Chita\n",
      "Asia/Choibalsan\n",
      "Asia/Chongqing\n",
      "Asia/Chungking\n",
      "Asia/Colombo\n",
      "Asia/Dacca\n",
      "Asia/Damascus\n",
      "Asia/Dhaka\n",
      "Asia/Dili\n",
      "Asia/Dubai\n",
      "Asia/Dushanbe\n",
      "Asia/Famagusta\n",
      "Asia/Gaza\n",
      "Asia/Harbin\n",
      "Asia/Hebron\n",
      "Asia/Ho_Chi_Minh\n",
      "Asia/Hong_Kong\n",
      "Asia/Hovd\n",
      "Asia/Irkutsk\n",
      "Asia/Istanbul\n",
      "Asia/Jakarta\n",
      "Asia/Jayapura\n",
      "Asia/Jerusalem\n",
      "Asia/Kabul\n",
      "Asia/Kamchatka\n",
      "Asia/Karachi\n",
      "Asia/Kashgar\n",
      "Asia/Kathmandu\n",
      "Asia/Katmandu\n",
      "Asia/Khandyga\n",
      "Asia/Kolkata\n",
      "Asia/Krasnoyarsk\n",
      "Asia/Kuala_Lumpur\n",
      "Asia/Kuching\n",
      "Asia/Kuwait\n",
      "Asia/Macao\n",
      "Asia/Macau\n",
      "Asia/Magadan\n",
      "Asia/Makassar\n",
      "Asia/Manila\n",
      "Asia/Muscat\n",
      "Asia/Nicosia\n",
      "Asia/Novokuznetsk\n",
      "Asia/Novosibirsk\n",
      "Asia/Omsk\n",
      "Asia/Oral\n",
      "Asia/Phnom_Penh\n",
      "Asia/Pontianak\n",
      "Asia/Pyongyang\n",
      "Asia/Qatar\n",
      "Asia/Qostanay\n",
      "Asia/Qyzylorda\n",
      "Asia/Rangoon\n",
      "Asia/Riyadh\n",
      "Asia/Saigon\n",
      "Asia/Sakhalin\n",
      "Asia/Samarkand\n",
      "Asia/Seoul\n",
      "Asia/Shanghai\n",
      "Asia/Singapore\n",
      "Asia/Srednekolymsk\n",
      "Asia/Taipei\n",
      "Asia/Tashkent\n",
      "Asia/Tbilisi\n",
      "Asia/Tehran\n",
      "Asia/Tel_Aviv\n",
      "Asia/Thimbu\n",
      "Asia/Thimphu\n",
      "Asia/Tokyo\n",
      "Asia/Tomsk\n",
      "Asia/Ujung_Pandang\n",
      "Asia/Ulaanbaatar\n",
      "Asia/Ulan_Bator\n",
      "Asia/Urumqi\n",
      "Asia/Ust-Nera\n",
      "Asia/Vientiane\n",
      "Asia/Vladivostok\n",
      "Asia/Yakutsk\n",
      "Asia/Yangon\n",
      "Asia/Yekaterinburg\n",
      "Asia/Yerevan\n",
      "Atlantic/Azores\n",
      "Atlantic/Bermuda\n",
      "Atlantic/Canary\n",
      "Atlantic/Cape_Verde\n",
      "Atlantic/Faeroe\n",
      "Atlantic/Faroe\n",
      "Atlantic/Jan_Mayen\n",
      "Atlantic/Madeira\n",
      "Atlantic/Reykjavik\n",
      "Atlantic/South_Georgia\n",
      "Atlantic/St_Helena\n",
      "Atlantic/Stanley\n",
      "Australia/ACT\n",
      "Australia/Adelaide\n",
      "Australia/Brisbane\n",
      "Australia/Broken_Hill\n",
      "Australia/Canberra\n",
      "Australia/Currie\n",
      "Australia/Darwin\n",
      "Australia/Eucla\n",
      "Australia/Hobart\n",
      "Australia/LHI\n",
      "Australia/Lindeman\n",
      "Australia/Lord_Howe\n",
      "Australia/Melbourne\n",
      "Australia/NSW\n",
      "Australia/North\n",
      "Australia/Perth\n",
      "Australia/Queensland\n",
      "Australia/South\n",
      "Australia/Sydney\n",
      "Australia/Tasmania\n",
      "Australia/Victoria\n",
      "Australia/West\n",
      "Australia/Yancowinna\n",
      "Brazil/Acre\n",
      "Brazil/DeNoronha\n",
      "Brazil/East\n",
      "Brazil/West\n",
      "CET\n",
      "CST6CDT\n",
      "Canada/Atlantic\n",
      "Canada/Central\n",
      "Canada/Eastern\n",
      "Canada/Mountain\n",
      "Canada/Newfoundland\n",
      "Canada/Pacific\n",
      "Canada/Saskatchewan\n",
      "Canada/Yukon\n",
      "Chile/Continental\n",
      "Chile/EasterIsland\n",
      "Cuba\n",
      "EET\n",
      "EST\n",
      "EST5EDT\n",
      "Egypt\n",
      "Eire\n",
      "Etc/GMT\n",
      "Etc/GMT+0\n",
      "Etc/GMT+1\n",
      "Etc/GMT+10\n",
      "Etc/GMT+11\n",
      "Etc/GMT+12\n",
      "Etc/GMT+2\n",
      "Etc/GMT+3\n",
      "Etc/GMT+4\n",
      "Etc/GMT+5\n",
      "Etc/GMT+6\n",
      "Etc/GMT+7\n",
      "Etc/GMT+8\n",
      "Etc/GMT+9\n",
      "Etc/GMT-0\n",
      "Etc/GMT-1\n",
      "Etc/GMT-10\n",
      "Etc/GMT-11\n",
      "Etc/GMT-12\n",
      "Etc/GMT-13\n",
      "Etc/GMT-14\n",
      "Etc/GMT-2\n",
      "Etc/GMT-3\n",
      "Etc/GMT-4\n",
      "Etc/GMT-5\n",
      "Etc/GMT-6\n",
      "Etc/GMT-7\n",
      "Etc/GMT-8\n",
      "Etc/GMT-9\n",
      "Etc/GMT0\n",
      "Etc/Greenwich\n",
      "Etc/UCT\n",
      "Etc/UTC\n",
      "Etc/Universal\n",
      "Etc/Zulu\n",
      "Europe/Amsterdam\n",
      "Europe/Andorra\n",
      "Europe/Astrakhan\n",
      "Europe/Athens\n",
      "Europe/Belfast\n",
      "Europe/Belgrade\n",
      "Europe/Berlin\n",
      "Europe/Bratislava\n",
      "Europe/Brussels\n",
      "Europe/Bucharest\n",
      "Europe/Budapest\n",
      "Europe/Busingen\n",
      "Europe/Chisinau\n",
      "Europe/Copenhagen\n",
      "Europe/Dublin\n",
      "Europe/Gibraltar\n",
      "Europe/Guernsey\n",
      "Europe/Helsinki\n",
      "Europe/Isle_of_Man\n",
      "Europe/Istanbul\n",
      "Europe/Jersey\n",
      "Europe/Kaliningrad\n",
      "Europe/Kiev\n",
      "Europe/Kirov\n",
      "Europe/Lisbon\n",
      "Europe/Ljubljana\n",
      "Europe/London\n",
      "Europe/Luxembourg\n",
      "Europe/Madrid\n",
      "Europe/Malta\n",
      "Europe/Mariehamn\n",
      "Europe/Minsk\n",
      "Europe/Monaco\n",
      "Europe/Moscow\n",
      "Europe/Nicosia\n",
      "Europe/Oslo\n",
      "Europe/Paris\n",
      "Europe/Podgorica\n",
      "Europe/Prague\n",
      "Europe/Riga\n",
      "Europe/Rome\n",
      "Europe/Samara\n",
      "Europe/San_Marino\n",
      "Europe/Sarajevo\n",
      "Europe/Saratov\n",
      "Europe/Simferopol\n",
      "Europe/Skopje\n",
      "Europe/Sofia\n",
      "Europe/Stockholm\n",
      "Europe/Tallinn\n",
      "Europe/Tirane\n",
      "Europe/Tiraspol\n",
      "Europe/Ulyanovsk\n",
      "Europe/Uzhgorod\n",
      "Europe/Vaduz\n",
      "Europe/Vatican\n",
      "Europe/Vienna\n",
      "Europe/Vilnius\n",
      "Europe/Volgograd\n",
      "Europe/Warsaw\n",
      "Europe/Zagreb\n",
      "Europe/Zaporozhye\n",
      "Europe/Zurich\n",
      "GB\n",
      "GB-Eire\n",
      "GMT\n",
      "GMT+0\n",
      "GMT-0\n",
      "GMT0\n",
      "Greenwich\n",
      "HST\n",
      "Hongkong\n",
      "Iceland\n",
      "Indian/Antananarivo\n",
      "Indian/Chagos\n",
      "Indian/Christmas\n",
      "Indian/Cocos\n",
      "Indian/Comoro\n",
      "Indian/Kerguelen\n",
      "Indian/Mahe\n",
      "Indian/Maldives\n",
      "Indian/Mauritius\n",
      "Indian/Mayotte\n",
      "Indian/Reunion\n",
      "Iran\n",
      "Israel\n",
      "Jamaica\n",
      "Japan\n",
      "Kwajalein\n",
      "Libya\n",
      "MET\n",
      "MST\n",
      "MST7MDT\n",
      "Mexico/BajaNorte\n",
      "Mexico/BajaSur\n",
      "Mexico/General\n",
      "NZ\n",
      "NZ-CHAT\n",
      "Navajo\n",
      "PRC\n",
      "PST8PDT\n",
      "Pacific/Apia\n",
      "Pacific/Auckland\n",
      "Pacific/Bougainville\n",
      "Pacific/Chatham\n",
      "Pacific/Chuuk\n",
      "Pacific/Easter\n",
      "Pacific/Efate\n",
      "Pacific/Enderbury\n",
      "Pacific/Fakaofo\n",
      "Pacific/Fiji\n",
      "Pacific/Funafuti\n",
      "Pacific/Galapagos\n",
      "Pacific/Gambier\n",
      "Pacific/Guadalcanal\n",
      "Pacific/Guam\n",
      "Pacific/Honolulu\n",
      "Pacific/Johnston\n",
      "Pacific/Kanton\n",
      "Pacific/Kiritimati\n",
      "Pacific/Kosrae\n",
      "Pacific/Kwajalein\n",
      "Pacific/Majuro\n",
      "Pacific/Marquesas\n",
      "Pacific/Midway\n",
      "Pacific/Nauru\n",
      "Pacific/Niue\n",
      "Pacific/Norfolk\n",
      "Pacific/Noumea\n",
      "Pacific/Pago_Pago\n",
      "Pacific/Palau\n",
      "Pacific/Pitcairn\n",
      "Pacific/Pohnpei\n",
      "Pacific/Ponape\n",
      "Pacific/Port_Moresby\n",
      "Pacific/Rarotonga\n",
      "Pacific/Saipan\n",
      "Pacific/Samoa\n",
      "Pacific/Tahiti\n",
      "Pacific/Tarawa\n",
      "Pacific/Tongatapu\n",
      "Pacific/Truk\n",
      "Pacific/Wake\n",
      "Pacific/Wallis\n",
      "Pacific/Yap\n",
      "Poland\n",
      "Portugal\n",
      "ROC\n",
      "ROK\n",
      "Singapore\n",
      "Turkey\n",
      "UCT\n",
      "US/Alaska\n",
      "US/Aleutian\n",
      "US/Arizona\n",
      "US/Central\n",
      "US/East-Indiana\n",
      "US/Eastern\n",
      "US/Hawaii\n",
      "US/Indiana-Starke\n",
      "US/Michigan\n",
      "US/Mountain\n",
      "US/Pacific\n",
      "US/Samoa\n",
      "UTC\n",
      "Universal\n",
      "W-SU\n",
      "WET\n",
      "Zulu\n"
     ]
    }
   ],
   "source": [
    "for tz in pytz.all_timezones:\n",
    "    print(tz)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f18fa2c9",
   "metadata": {},
   "source": [
    "With the `zoneinfo` module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9d2cf9d1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Africa/Abidjan\n",
      "Africa/Accra\n",
      "Africa/Addis_Ababa\n",
      "Africa/Algiers\n",
      "Africa/Asmara\n",
      "Africa/Asmera\n",
      "Africa/Bamako\n",
      "Africa/Bangui\n",
      "Africa/Banjul\n",
      "Africa/Bissau\n",
      "Africa/Blantyre\n",
      "Africa/Brazzaville\n",
      "Africa/Bujumbura\n",
      "Africa/Cairo\n",
      "Africa/Casablanca\n",
      "Africa/Ceuta\n",
      "Africa/Conakry\n",
      "Africa/Dakar\n",
      "Africa/Dar_es_Salaam\n",
      "Africa/Djibouti\n",
      "Africa/Douala\n",
      "Africa/El_Aaiun\n",
      "Africa/Freetown\n",
      "Africa/Gaborone\n",
      "Africa/Harare\n",
      "Africa/Johannesburg\n",
      "Africa/Juba\n",
      "Africa/Kampala\n",
      "Africa/Khartoum\n",
      "Africa/Kigali\n",
      "Africa/Kinshasa\n",
      "Africa/Lagos\n",
      "Africa/Libreville\n",
      "Africa/Lome\n",
      "Africa/Luanda\n",
      "Africa/Lubumbashi\n",
      "Africa/Lusaka\n",
      "Africa/Malabo\n",
      "Africa/Maputo\n",
      "Africa/Maseru\n",
      "Africa/Mbabane\n",
      "Africa/Mogadishu\n",
      "Africa/Monrovia\n",
      "Africa/Nairobi\n",
      "Africa/Ndjamena\n",
      "Africa/Niamey\n",
      "Africa/Nouakchott\n",
      "Africa/Ouagadougou\n",
      "Africa/Porto-Novo\n",
      "Africa/Sao_Tome\n",
      "Africa/Timbuktu\n",
      "Africa/Tripoli\n",
      "Africa/Tunis\n",
      "Africa/Windhoek\n",
      "America/Adak\n",
      "America/Anchorage\n",
      "America/Anguilla\n",
      "America/Antigua\n",
      "America/Araguaina\n",
      "America/Argentina/Buenos_Aires\n",
      "America/Argentina/Catamarca\n",
      "America/Argentina/ComodRivadavia\n",
      "America/Argentina/Cordoba\n",
      "America/Argentina/Jujuy\n",
      "America/Argentina/La_Rioja\n",
      "America/Argentina/Mendoza\n",
      "America/Argentina/Rio_Gallegos\n",
      "America/Argentina/Salta\n",
      "America/Argentina/San_Juan\n",
      "America/Argentina/San_Luis\n",
      "America/Argentina/Tucuman\n",
      "America/Argentina/Ushuaia\n",
      "America/Aruba\n",
      "America/Asuncion\n",
      "America/Atikokan\n",
      "America/Atka\n",
      "America/Bahia\n",
      "America/Bahia_Banderas\n",
      "America/Barbados\n",
      "America/Belem\n",
      "America/Belize\n",
      "America/Blanc-Sablon\n",
      "America/Boa_Vista\n",
      "America/Bogota\n",
      "America/Boise\n",
      "America/Buenos_Aires\n",
      "America/Cambridge_Bay\n",
      "America/Campo_Grande\n",
      "America/Cancun\n",
      "America/Caracas\n",
      "America/Catamarca\n",
      "America/Cayenne\n",
      "America/Cayman\n",
      "America/Chicago\n",
      "America/Chihuahua\n",
      "America/Coral_Harbour\n",
      "America/Cordoba\n",
      "America/Costa_Rica\n",
      "America/Creston\n",
      "America/Cuiaba\n",
      "America/Curacao\n",
      "America/Danmarkshavn\n",
      "America/Dawson\n",
      "America/Dawson_Creek\n",
      "America/Denver\n",
      "America/Detroit\n",
      "America/Dominica\n",
      "America/Edmonton\n",
      "America/Eirunepe\n",
      "America/El_Salvador\n",
      "America/Ensenada\n",
      "America/Fort_Nelson\n",
      "America/Fort_Wayne\n",
      "America/Fortaleza\n",
      "America/Glace_Bay\n",
      "America/Godthab\n",
      "America/Goose_Bay\n",
      "America/Grand_Turk\n",
      "America/Grenada\n",
      "America/Guadeloupe\n",
      "America/Guatemala\n",
      "America/Guayaquil\n",
      "America/Guyana\n",
      "America/Halifax\n",
      "America/Havana\n",
      "America/Hermosillo\n",
      "America/Indiana/Indianapolis\n",
      "America/Indiana/Knox\n",
      "America/Indiana/Marengo\n",
      "America/Indiana/Petersburg\n",
      "America/Indiana/Tell_City\n",
      "America/Indiana/Vevay\n",
      "America/Indiana/Vincennes\n",
      "America/Indiana/Winamac\n",
      "America/Indianapolis\n",
      "America/Inuvik\n",
      "America/Iqaluit\n",
      "America/Jamaica\n",
      "America/Jujuy\n",
      "America/Juneau\n",
      "America/Kentucky/Louisville\n",
      "America/Kentucky/Monticello\n",
      "America/Knox_IN\n",
      "America/Kralendijk\n",
      "America/La_Paz\n",
      "America/Lima\n",
      "America/Los_Angeles\n",
      "America/Louisville\n",
      "America/Lower_Princes\n",
      "America/Maceio\n",
      "America/Managua\n",
      "America/Manaus\n",
      "America/Marigot\n",
      "America/Martinique\n",
      "America/Matamoros\n",
      "America/Mazatlan\n",
      "America/Mendoza\n",
      "America/Menominee\n",
      "America/Merida\n",
      "America/Metlakatla\n",
      "America/Mexico_City\n",
      "America/Miquelon\n",
      "America/Moncton\n",
      "America/Monterrey\n",
      "America/Montevideo\n",
      "America/Montreal\n",
      "America/Montserrat\n",
      "America/Nassau\n",
      "America/New_York\n",
      "America/Nipigon\n",
      "America/Nome\n",
      "America/Noronha\n",
      "America/North_Dakota/Beulah\n",
      "America/North_Dakota/Center\n",
      "America/North_Dakota/New_Salem\n",
      "America/Nuuk\n",
      "America/Ojinaga\n",
      "America/Panama\n",
      "America/Pangnirtung\n",
      "America/Paramaribo\n",
      "America/Phoenix\n",
      "America/Port-au-Prince\n",
      "America/Port_of_Spain\n",
      "America/Porto_Acre\n",
      "America/Porto_Velho\n",
      "America/Puerto_Rico\n",
      "America/Punta_Arenas\n",
      "America/Rainy_River\n",
      "America/Rankin_Inlet\n",
      "America/Recife\n",
      "America/Regina\n",
      "America/Resolute\n",
      "America/Rio_Branco\n",
      "America/Rosario\n",
      "America/Santa_Isabel\n",
      "America/Santarem\n",
      "America/Santiago\n",
      "America/Santo_Domingo\n",
      "America/Sao_Paulo\n",
      "America/Scoresbysund\n",
      "America/Shiprock\n",
      "America/Sitka\n",
      "America/St_Barthelemy\n",
      "America/St_Johns\n",
      "America/St_Kitts\n",
      "America/St_Lucia\n",
      "America/St_Thomas\n",
      "America/St_Vincent\n",
      "America/Swift_Current\n",
      "America/Tegucigalpa\n",
      "America/Thule\n",
      "America/Thunder_Bay\n",
      "America/Tijuana\n",
      "America/Toronto\n",
      "America/Tortola\n",
      "America/Vancouver\n",
      "America/Virgin\n",
      "America/Whitehorse\n",
      "America/Winnipeg\n",
      "America/Yakutat\n",
      "America/Yellowknife\n",
      "Antarctica/Casey\n",
      "Antarctica/Davis\n",
      "Antarctica/DumontDUrville\n",
      "Antarctica/Macquarie\n",
      "Antarctica/Mawson\n",
      "Antarctica/McMurdo\n",
      "Antarctica/Palmer\n",
      "Antarctica/Rothera\n",
      "Antarctica/South_Pole\n",
      "Antarctica/Syowa\n",
      "Antarctica/Troll\n",
      "Antarctica/Vostok\n",
      "Arctic/Longyearbyen\n",
      "Asia/Aden\n",
      "Asia/Almaty\n",
      "Asia/Amman\n",
      "Asia/Anadyr\n",
      "Asia/Aqtau\n",
      "Asia/Aqtobe\n",
      "Asia/Ashgabat\n",
      "Asia/Ashkhabad\n",
      "Asia/Atyrau\n",
      "Asia/Baghdad\n",
      "Asia/Bahrain\n",
      "Asia/Baku\n",
      "Asia/Bangkok\n",
      "Asia/Barnaul\n",
      "Asia/Beirut\n",
      "Asia/Bishkek\n",
      "Asia/Brunei\n",
      "Asia/Calcutta\n",
      "Asia/Chita\n",
      "Asia/Choibalsan\n",
      "Asia/Chongqing\n",
      "Asia/Chungking\n",
      "Asia/Colombo\n",
      "Asia/Dacca\n",
      "Asia/Damascus\n",
      "Asia/Dhaka\n",
      "Asia/Dili\n",
      "Asia/Dubai\n",
      "Asia/Dushanbe\n",
      "Asia/Famagusta\n",
      "Asia/Gaza\n",
      "Asia/Harbin\n",
      "Asia/Hebron\n",
      "Asia/Ho_Chi_Minh\n",
      "Asia/Hong_Kong\n",
      "Asia/Hovd\n",
      "Asia/Irkutsk\n",
      "Asia/Istanbul\n",
      "Asia/Jakarta\n",
      "Asia/Jayapura\n",
      "Asia/Jerusalem\n",
      "Asia/Kabul\n",
      "Asia/Kamchatka\n",
      "Asia/Karachi\n",
      "Asia/Kashgar\n",
      "Asia/Kathmandu\n",
      "Asia/Katmandu\n",
      "Asia/Khandyga\n",
      "Asia/Kolkata\n",
      "Asia/Krasnoyarsk\n",
      "Asia/Kuala_Lumpur\n",
      "Asia/Kuching\n",
      "Asia/Kuwait\n",
      "Asia/Macao\n",
      "Asia/Macau\n",
      "Asia/Magadan\n",
      "Asia/Makassar\n",
      "Asia/Manila\n",
      "Asia/Muscat\n",
      "Asia/Nicosia\n",
      "Asia/Novokuznetsk\n",
      "Asia/Novosibirsk\n",
      "Asia/Omsk\n",
      "Asia/Oral\n",
      "Asia/Phnom_Penh\n",
      "Asia/Pontianak\n",
      "Asia/Pyongyang\n",
      "Asia/Qatar\n",
      "Asia/Qostanay\n",
      "Asia/Qyzylorda\n",
      "Asia/Rangoon\n",
      "Asia/Riyadh\n",
      "Asia/Saigon\n",
      "Asia/Sakhalin\n",
      "Asia/Samarkand\n",
      "Asia/Seoul\n",
      "Asia/Shanghai\n",
      "Asia/Singapore\n",
      "Asia/Srednekolymsk\n",
      "Asia/Taipei\n",
      "Asia/Tashkent\n",
      "Asia/Tbilisi\n",
      "Asia/Tehran\n",
      "Asia/Tel_Aviv\n",
      "Asia/Thimbu\n",
      "Asia/Thimphu\n",
      "Asia/Tokyo\n",
      "Asia/Tomsk\n",
      "Asia/Ujung_Pandang\n",
      "Asia/Ulaanbaatar\n",
      "Asia/Ulan_Bator\n",
      "Asia/Urumqi\n",
      "Asia/Ust-Nera\n",
      "Asia/Vientiane\n",
      "Asia/Vladivostok\n",
      "Asia/Yakutsk\n",
      "Asia/Yangon\n",
      "Asia/Yekaterinburg\n",
      "Asia/Yerevan\n",
      "Atlantic/Azores\n",
      "Atlantic/Bermuda\n",
      "Atlantic/Canary\n",
      "Atlantic/Cape_Verde\n",
      "Atlantic/Faeroe\n",
      "Atlantic/Faroe\n",
      "Atlantic/Jan_Mayen\n",
      "Atlantic/Madeira\n",
      "Atlantic/Reykjavik\n",
      "Atlantic/South_Georgia\n",
      "Atlantic/St_Helena\n",
      "Atlantic/Stanley\n",
      "Australia/ACT\n",
      "Australia/Adelaide\n",
      "Australia/Brisbane\n",
      "Australia/Broken_Hill\n",
      "Australia/Canberra\n",
      "Australia/Currie\n",
      "Australia/Darwin\n",
      "Australia/Eucla\n",
      "Australia/Hobart\n",
      "Australia/LHI\n",
      "Australia/Lindeman\n",
      "Australia/Lord_Howe\n",
      "Australia/Melbourne\n",
      "Australia/NSW\n",
      "Australia/North\n",
      "Australia/Perth\n",
      "Australia/Queensland\n",
      "Australia/South\n",
      "Australia/Sydney\n",
      "Australia/Tasmania\n",
      "Australia/Victoria\n",
      "Australia/West\n",
      "Australia/Yancowinna\n",
      "Brazil/Acre\n",
      "Brazil/DeNoronha\n",
      "Brazil/East\n",
      "Brazil/West\n",
      "CET\n",
      "CST6CDT\n",
      "Canada/Atlantic\n",
      "Canada/Central\n",
      "Canada/Eastern\n",
      "Canada/Mountain\n",
      "Canada/Newfoundland\n",
      "Canada/Pacific\n",
      "Canada/Saskatchewan\n",
      "Canada/Yukon\n",
      "Chile/Continental\n",
      "Chile/EasterIsland\n",
      "Cuba\n",
      "EET\n",
      "EST\n",
      "EST5EDT\n",
      "Egypt\n",
      "Eire\n",
      "Etc/GMT\n",
      "Etc/GMT+0\n",
      "Etc/GMT+1\n",
      "Etc/GMT+10\n",
      "Etc/GMT+11\n",
      "Etc/GMT+12\n",
      "Etc/GMT+2\n",
      "Etc/GMT+3\n",
      "Etc/GMT+4\n",
      "Etc/GMT+5\n",
      "Etc/GMT+6\n",
      "Etc/GMT+7\n",
      "Etc/GMT+8\n",
      "Etc/GMT+9\n",
      "Etc/GMT-0\n",
      "Etc/GMT-1\n",
      "Etc/GMT-10\n",
      "Etc/GMT-11\n",
      "Etc/GMT-12\n",
      "Etc/GMT-13\n",
      "Etc/GMT-14\n",
      "Etc/GMT-2\n",
      "Etc/GMT-3\n",
      "Etc/GMT-4\n",
      "Etc/GMT-5\n",
      "Etc/GMT-6\n",
      "Etc/GMT-7\n",
      "Etc/GMT-8\n",
      "Etc/GMT-9\n",
      "Etc/GMT0\n",
      "Etc/Greenwich\n",
      "Etc/UCT\n",
      "Etc/UTC\n",
      "Etc/Universal\n",
      "Etc/Zulu\n",
      "Europe/Amsterdam\n",
      "Europe/Andorra\n",
      "Europe/Astrakhan\n",
      "Europe/Athens\n",
      "Europe/Belfast\n",
      "Europe/Belgrade\n",
      "Europe/Berlin\n",
      "Europe/Bratislava\n",
      "Europe/Brussels\n",
      "Europe/Bucharest\n",
      "Europe/Budapest\n",
      "Europe/Busingen\n",
      "Europe/Chisinau\n",
      "Europe/Copenhagen\n",
      "Europe/Dublin\n",
      "Europe/Gibraltar\n",
      "Europe/Guernsey\n",
      "Europe/Helsinki\n",
      "Europe/Isle_of_Man\n",
      "Europe/Istanbul\n",
      "Europe/Jersey\n",
      "Europe/Kaliningrad\n",
      "Europe/Kiev\n",
      "Europe/Kirov\n",
      "Europe/Lisbon\n",
      "Europe/Ljubljana\n",
      "Europe/London\n",
      "Europe/Luxembourg\n",
      "Europe/Madrid\n",
      "Europe/Malta\n",
      "Europe/Mariehamn\n",
      "Europe/Minsk\n",
      "Europe/Monaco\n",
      "Europe/Moscow\n",
      "Europe/Nicosia\n",
      "Europe/Oslo\n",
      "Europe/Paris\n",
      "Europe/Podgorica\n",
      "Europe/Prague\n",
      "Europe/Riga\n",
      "Europe/Rome\n",
      "Europe/Samara\n",
      "Europe/San_Marino\n",
      "Europe/Sarajevo\n",
      "Europe/Saratov\n",
      "Europe/Simferopol\n",
      "Europe/Skopje\n",
      "Europe/Sofia\n",
      "Europe/Stockholm\n",
      "Europe/Tallinn\n",
      "Europe/Tirane\n",
      "Europe/Tiraspol\n",
      "Europe/Ulyanovsk\n",
      "Europe/Uzhgorod\n",
      "Europe/Vaduz\n",
      "Europe/Vatican\n",
      "Europe/Vienna\n",
      "Europe/Vilnius\n",
      "Europe/Volgograd\n",
      "Europe/Warsaw\n",
      "Europe/Zagreb\n",
      "Europe/Zaporozhye\n",
      "Europe/Zurich\n",
      "Factory\n",
      "GB\n",
      "GB-Eire\n",
      "GMT\n",
      "GMT+0\n",
      "GMT-0\n",
      "GMT0\n",
      "Greenwich\n",
      "HST\n",
      "Hongkong\n",
      "Iceland\n",
      "Indian/Antananarivo\n",
      "Indian/Chagos\n",
      "Indian/Christmas\n",
      "Indian/Cocos\n",
      "Indian/Comoro\n",
      "Indian/Kerguelen\n",
      "Indian/Mahe\n",
      "Indian/Maldives\n",
      "Indian/Mauritius\n",
      "Indian/Mayotte\n",
      "Indian/Reunion\n",
      "Iran\n",
      "Israel\n",
      "Jamaica\n",
      "Japan\n",
      "Kwajalein\n",
      "Libya\n",
      "MET\n",
      "MST\n",
      "MST7MDT\n",
      "Mexico/BajaNorte\n",
      "Mexico/BajaSur\n",
      "Mexico/General\n",
      "NZ\n",
      "NZ-CHAT\n",
      "Navajo\n",
      "PRC\n",
      "PST8PDT\n",
      "Pacific/Apia\n",
      "Pacific/Auckland\n",
      "Pacific/Bougainville\n",
      "Pacific/Chatham\n",
      "Pacific/Chuuk\n",
      "Pacific/Easter\n",
      "Pacific/Efate\n",
      "Pacific/Enderbury\n",
      "Pacific/Fakaofo\n",
      "Pacific/Fiji\n",
      "Pacific/Funafuti\n",
      "Pacific/Galapagos\n",
      "Pacific/Gambier\n",
      "Pacific/Guadalcanal\n",
      "Pacific/Guam\n",
      "Pacific/Honolulu\n",
      "Pacific/Johnston\n",
      "Pacific/Kanton\n",
      "Pacific/Kiritimati\n",
      "Pacific/Kosrae\n",
      "Pacific/Kwajalein\n",
      "Pacific/Majuro\n",
      "Pacific/Marquesas\n",
      "Pacific/Midway\n",
      "Pacific/Nauru\n",
      "Pacific/Niue\n",
      "Pacific/Norfolk\n",
      "Pacific/Noumea\n",
      "Pacific/Pago_Pago\n",
      "Pacific/Palau\n",
      "Pacific/Pitcairn\n",
      "Pacific/Pohnpei\n",
      "Pacific/Ponape\n",
      "Pacific/Port_Moresby\n",
      "Pacific/Rarotonga\n",
      "Pacific/Saipan\n",
      "Pacific/Samoa\n",
      "Pacific/Tahiti\n",
      "Pacific/Tarawa\n",
      "Pacific/Tongatapu\n",
      "Pacific/Truk\n",
      "Pacific/Wake\n",
      "Pacific/Wallis\n",
      "Pacific/Yap\n",
      "Poland\n",
      "Portugal\n",
      "ROC\n",
      "ROK\n",
      "Singapore\n",
      "Turkey\n",
      "UCT\n",
      "US/Alaska\n",
      "US/Aleutian\n",
      "US/Arizona\n",
      "US/Central\n",
      "US/East-Indiana\n",
      "US/Eastern\n",
      "US/Hawaii\n",
      "US/Indiana-Starke\n",
      "US/Michigan\n",
      "US/Mountain\n",
      "US/Pacific\n",
      "US/Samoa\n",
      "UTC\n",
      "Universal\n",
      "W-SU\n",
      "WET\n",
      "Zulu\n"
     ]
    }
   ],
   "source": [
    "for tz in sorted(zoneinfo.available_timezones()):\n",
    "    print(tz)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a1887cf",
   "metadata": {},
   "source": [
    "Are the time zones defined by `pytz` and `zoneinfo` the same? Yes!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f8df276",
   "metadata": {},
   "source": [
    "In this example, let's take our current time in UTC, and convert it to some other time zone, say `Australia/Melbourne`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "77f1b8d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "now_utc_naive = datetime.utcnow()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f8586215",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 6, 1, 3, 368403)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now_utc_naive"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a452220a",
   "metadata": {},
   "source": [
    "The problem here is that we have a _naive_ datetime (i.e. one without an attached timezone)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1d10809",
   "metadata": {},
   "source": [
    "We can make this naive datetime time zone aware by tacking on the timezone (since we know it is UTC):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "db60736b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 6, 1, 3, 368403, tzinfo=datetime.timezone.utc)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now_utc_aware = now_utc_naive.replace(tzinfo=timezone.utc)\n",
    "now_utc_aware"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8282b097",
   "metadata": {},
   "source": [
    "Or, we could use the `pytz` library to do the same thing:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0d7434f7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 6, 1, 3, 377626, tzinfo=<UTC>)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pytz.utc.localize(datetime.utcnow())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e613c2e1",
   "metadata": {},
   "source": [
    "Now that we have a time zone aware datetime, we can convert it to another timezone using `pytz`:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94b0b5c9",
   "metadata": {},
   "source": [
    "First, let's pick a time zone from `pytz`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "833b5ff9",
   "metadata": {},
   "outputs": [],
   "source": [
    "tz_melbourne = pytz.timezone('Australia/Melbourne')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce4323c1",
   "metadata": {},
   "source": [
    "And now we localize our aware datetime to this time zone:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d23fd3c4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 17, 1, 3, 368403, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now_utc_aware.astimezone(tz_melbourne)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "260bd7ff",
   "metadata": {},
   "source": [
    "We could do both these steps in a single expression:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "6559daf7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 17, 1, 3, 368403, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now_utc_aware.astimezone(pytz.timezone('Australia/Melbourne'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6be99718",
   "metadata": {},
   "source": [
    "Now, let's do the same thing using the `zoneinfo` module."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c9b22bb",
   "metadata": {},
   "source": [
    "Let's pick the same target time zone:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "30c58db3",
   "metadata": {},
   "outputs": [],
   "source": [
    "tz_zi_dublin = ZoneInfo(\"Europe/Dublin\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f77b5b0",
   "metadata": {},
   "source": [
    "And the let's convert our aware datetime to that time zone:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "1623322d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 6, 1, 3, 368403, tzinfo=zoneinfo.ZoneInfo(key='Europe/Dublin'))"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now_utc_aware.astimezone(tz_zi_dublin)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4536470f",
   "metadata": {},
   "source": [
    "Or, we can also write this as a single expression:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "337c3955",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2022, 3, 20, 6, 1, 3, 368403, tzinfo=zoneinfo.ZoneInfo(key='Europe/Dublin'))"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now_utc_aware.astimezone(ZoneInfo(\"Europe/Dublin\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4076195d",
   "metadata": {},
   "source": [
    "#### The `math` Module"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41d86e28",
   "metadata": {},
   "source": [
    "Several enhancements or additions have been to the math library."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd3de95f",
   "metadata": {},
   "source": [
    "The `math` module already had the `gcd` function to calculate the great common divisor of two numbers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "911df27e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4154629e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "math.gcd(27, 45)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "85abe1fa",
   "metadata": {},
   "source": [
    "But now `gcd` can take multiple arguments, not just two:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "d64ea0d9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "math.gcd(27, 45, 18, 15)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0503d78a",
   "metadata": {},
   "source": [
    "The `lcm` (least common multiple) function has been added:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "b4c25fef",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "math.lcm(2, 3, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58a4c3cd",
   "metadata": {},
   "source": [
    "#### Dictionary Unions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c05f130",
   "metadata": {},
   "source": [
    "When we discussed dictionaries in this course, we saw that we could combine two dictionaries using unpacking:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "136c8836",
   "metadata": {},
   "outputs": [],
   "source": [
    "d1 = {'a': 1, 'b': 2, 'c': 3}\n",
    "d2 = {'c': 30, 'd': 40}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "81331802",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 2, 'c': 30, 'd': 40}"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{**d1, **d2}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97ca030f",
   "metadata": {},
   "source": [
    "As we saw the second dictionary's key/value pair \"overwrote\" the key/value pair from the first dictionary."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b361771e",
   "metadata": {},
   "source": [
    "We could also use the `ChainMap` function in the `collections` module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "d633f16c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import ChainMap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "ad250dfd",
   "metadata": {},
   "outputs": [],
   "source": [
    "merged = ChainMap(d1, d2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "1deeb8f2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 3, 40)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "merged['a'], merged['c'], merged['d']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1751d47a",
   "metadata": {},
   "source": [
    "As you can see, in the `ChainMap`, the firest occurrence of the key is used - so in this case `c` comes from `d1`, not `d2`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c63e893",
   "metadata": {},
   "source": [
    "Both of these ways of \"combining\" dictionaries work well - but they are not very intuitive, and need a little attention to what happens when you have common keys in the dictionaries."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aca5787b",
   "metadata": {},
   "source": [
    "Think of concatenating lists where we can simply use the `+` operator - this is very intuitive:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "de850747",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, 5, 6]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[1, 2, 3] + [4, 5, 6]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69429bab",
   "metadata": {},
   "source": [
    "Now dictionaries are not like lists, but they are closely related to **sets**. With sets, we have the **union** operator (`|`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "dcb8a7b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a', 'b', 'c', 'd'}"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s1 = {'a', 'b', 'c'}\n",
    "s2 = {'c', 'd'}\n",
    "\n",
    "s1 | s2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32c20dfb",
   "metadata": {},
   "source": [
    "Python 3.9 introduces support for the **union** (`|`) operation between dictionaries as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "af3fcc01",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 2, 'c': 30, 'd': 40}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d1 | d2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "851ffadc",
   "metadata": {},
   "source": [
    "Just like with the `{**d1, **d2}` approach, the value for `c` came from the second dictionary."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb6fc060",
   "metadata": {},
   "source": [
    "And just like with that technique we can control this by switching the order of the dictionaries in the union:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "05555100",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'c': 3, 'd': 40, 'a': 1, 'b': 2}"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d2 | d1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "739e210f",
   "metadata": {},
   "source": [
    "One question we should have, is what happens to the insertion order that Python dictionaries now guarantee?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "f8759da5",
   "metadata": {},
   "outputs": [],
   "source": [
    "d1 = {'c': 3, 'a': 1, 'b': 2}\n",
    "d2 = {'d': 40, 'c': 30}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "e06e3966",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'c': 30, 'a': 1, 'b': 2, 'd': 40}"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d1 | d2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e0e1c2e",
   "metadata": {},
   "source": [
    "As you can see, even though the **value** for `c` came from the **second** dictionary, the original inertion order of the **keys** is maintained, so `c` is still in first position in the union of the two dictionaries."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e12dee6a",
   "metadata": {},
   "source": [
    "#### String Methods"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f69f79e4",
   "metadata": {},
   "source": [
    "Often we need to remove some prefix or suffix in a string."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "67496793",
   "metadata": {},
   "source": [
    "For example, we may have this list of string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "9da4cabe",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = [\n",
    "    \"(log) [2022-03-01T13:30:01] Log record 1\",\n",
    "    \"(log) [2022-03-01T13:30:02] Log record 2\",\n",
    "    \"(log) [2022-03-01T13:30:03] Log record 3\",\n",
    "    \"(log) [2022-03-01T13:30:04] Log record 4\",\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30de1de8",
   "metadata": {},
   "source": [
    "And we want to clean these up and remove the `(log) ` prefix (including the space)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84a6c502",
   "metadata": {},
   "source": [
    "We can certainly do it this way:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "8a60ecdc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['[2022-03-01T13:30:01] Log record 1',\n",
       " '[2022-03-01T13:30:02] Log record 2',\n",
       " '[2022-03-01T13:30:03] Log record 3',\n",
       " '[2022-03-01T13:30:04] Log record 4']"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clean = [\n",
    "    s.replace(\"(log) \", '')\n",
    "    for s in data\n",
    "]\n",
    "clean"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45fa082e",
   "metadata": {},
   "source": [
    "You might be tempted to use the `lstrip` method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "74e60a43",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['[2022-03-01T13:30:01] Log record 1',\n",
       " '[2022-03-01T13:30:02] Log record 2',\n",
       " '[2022-03-01T13:30:03] Log record 3',\n",
       " '[2022-03-01T13:30:04] Log record 4']"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clean = [\n",
    "    s.lstrip(\"(log) \")\n",
    "    for s in data\n",
    "]\n",
    "clean"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e045ebc",
   "metadata": {},
   "source": [
    "This appears to work, but `lstrip` (and `rstrip`) does not interpet `\"(log )\"` as a string, but rather a **sequence** of characters, and each one will be removed - so you might end up with this problem:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "ddc6e3a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "data2 = [\n",
    "    \"(log) log: [2022-03-01T13:30:01] Log record 1\",\n",
    "    \"(log) log: [2022-03-01T13:30:02] Log record 2\",\n",
    "    \"(log) log: [2022-03-01T13:30:03] Log record 3\",\n",
    "    \"(log) log: [2022-03-01T13:30:04] Log record 4\",\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "d87cd3c5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[': [2022-03-01T13:30:01] Log record 1',\n",
       " ': [2022-03-01T13:30:02] Log record 2',\n",
       " ': [2022-03-01T13:30:03] Log record 3',\n",
       " ': [2022-03-01T13:30:04] Log record 4']"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clean = [\n",
    "    s.lstrip(\"(log) \")\n",
    "    for s in data2\n",
    "]\n",
    "clean"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f73aac3",
   "metadata": {},
   "source": [
    "Now that removed a lot more than expected everything from those strings, unlike the replace, which will replace only the first occurrence by default:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "eaf8792b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['log: [2022-03-01T13:30:01] Log record 1',\n",
       " 'log: [2022-03-01T13:30:02] Log record 2',\n",
       " 'log: [2022-03-01T13:30:03] Log record 3',\n",
       " 'log: [2022-03-01T13:30:04] Log record 4']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clean = [\n",
    "    s.replace(\"(log) \", '')\n",
    "    for s in data2\n",
    "]\n",
    "clean"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0aca0211",
   "metadata": {},
   "source": [
    "Python 3,9 introduces two new string methods to do this without having to use `replace`, namely the `removeprefix()` and `removesuffix()` methods:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "b320eb46",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['[2022-03-01T13:30:01] Log record 1',\n",
       " '[2022-03-01T13:30:02] Log record 2',\n",
       " '[2022-03-01T13:30:03] Log record 3',\n",
       " '[2022-03-01T13:30:04] Log record 4']"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[\n",
    "    s.removeprefix(\"(log) \")\n",
    "    for s in data\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "d4ebaf46",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['log: [2022-03-01T13:30:01] Log record 1',\n",
       " 'log: [2022-03-01T13:30:02] Log record 2',\n",
       " 'log: [2022-03-01T13:30:03] Log record 3',\n",
       " 'log: [2022-03-01T13:30:04] Log record 4']"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[\n",
    "    s.removeprefix(\"(log) \")\n",
    "    for s in data2\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7a2ffd4",
   "metadata": {},
   "source": [
    "Note that if the prefix (or suffix) is not found, nothing happens, the new string will be the same as the original (i.e. no exception is raised):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "829cb63b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Python rocks!'"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'Python rocks!'.removeprefix('Java')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
